#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>

#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <assert.h>

#include "event.h"
#include "reactor.h"

namespace reactor {

#define TIMEOUT_READ 30

void ReportSocketError(const char * msg){
    fprintf(stderr, "%s error: %s\n", msg, strerror(errno));
}

/// 所有socket都设置为非阻塞
inline int make_socket_non_blocking (int sfd){
    int flags, s;
    flags = fcntl (sfd, F_GETFL, 0);    //get file status sign
    if (flags == -1){
        perror ("fcntl");
        return -1;
    }

    flags |= O_NONBLOCK;    //set up file status sign
    s = fcntl (sfd, F_SETFL, flags);
    if (s == -1){
        perror ("fcntl");
        return -1;
    }
    return 0;
}

Event::Event(Reactor * reactor,int type)
    :m_reactor(reactor),m_timeout(0),m_update_time(false),on_write(0),on_read(0),on_error(0),on_timeout(0){
    setEventType(type);
}

void Event::setEventType(int event_type){
    /*check it has incompatible in ev*/
    bool is_valid = ((event_type & EV_PERSIST) && (event_type & EV_TIMEOUT)) ? false : true;
    assert(is_valid);
    if(event_type & EV_PERSIST)
        event_type |= EV_PERSIST;
    else
        event_type |= EV_TIMEOUT;
    m_event_type = event_type;
}

void * Event::write(void * data){
    if(on_write){
        return on_write(data);
    }
    return 0;
}

void * Event::read(void * data){
    if(on_read){
        return on_read(data);
    }
    return 0;
}

void * Event::error(void * data){
    if(on_error){
        return on_error(data);
    }
    return 0;
}

void * Event::timeout(void *data){
    if(on_timeout){
        return on_timeout(data);
    }
    return 0;
}

ServerEvent::ServerEvent(Reactor * reactor,int type, const std::string &ip, const int &port, void *rdata, void *wdata, void *tdata, void *edata)
    : Event(reactor,type),m_ip(ip),m_port(port),m_r_data(rdata),m_w_data(wdata),m_t_data(tdata),m_e_data(edata){

    m_handle = socket(AF_INET, SOCK_STREAM, 0);
    if(m_handle < 0){
        ReportSocketError("handle");
        exit(0);
    }
    make_socket_non_blocking(m_handle);
    int one = 1;
    setsockopt(m_handle, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(m_port);
    addr.sin_addr.s_addr = inet_addr(m_ip.c_str());
    if (bind(m_handle, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        ReportSocketError("bind");
    }

    if (listen(m_handle, 10) < 0)
    {
        ReportSocketError("listen");
    }
}

ServerEvent::~ServerEvent(){

}

void * ServerEvent::read(void *data){
    print_msg("new handle");
    struct sockaddr addr;
    socklen_t addrlen = sizeof(addr);
    reactor::Handle handle = accept(m_handle,&addr,&addrlen);
    if(handle <= 0){
        ReportSocketError("accept error");
    }
    make_socket_non_blocking(handle);
    /// 接受新的链接，构造，并注册事件，注意需要进行释放。尤其是在作为基础库设计的时候
    RWEvent * ev = new RWEvent(m_reactor,EV_READ | EV_TIMEOUT,handle);
    m_reactor->registerEvent(ev,TIMEOUT_READ);
    return data;
}

void * ServerEvent::timeout(void *data){
    print_msg("server timeout!");
    return data;
}

RWEvent::RWEvent(Reactor * reactor,int type, int handle, void *rdata, void *wdata, void *tdata, void *edata)
    :Event(reactor,type),m_recv_buff(0),m_recv_length(0),m_recv_offset(0),m_r_data(rdata),m_w_data(wdata),m_t_data(tdata),m_e_data(edata){
    m_handle = handle;
}
RWEvent::~RWEvent(){
    print_msg("delete!!");
}

void Event::closeEvent(){
    m_reactor->removeEvent(this);
    close(m_handle);
}

void * RWEvent::read(void *data){
    print_msg("read event!");
    const int size = 10240;
    char buff[size]={0};
    while(true){
        int ret = recv(m_handle,buff,size,0);
        if(ret == 0){
            print_msg("client disconnect!");
            closeEvent();
            break;
        } else if(ret < 0){
            if(errno == EAGAIN){
                print_msg("recv completed!");
                break;
                //如果不是持久事件，应该add(epollin)使其通知下一次读
            }
        } else{
            print_msg(buff);
            void * p = realloc(m_recv_buff,m_recv_length+ret);
            assert(p);
            m_recv_buff = (unsigned char *)p;
            memcpy(m_recv_buff + m_recv_length,buff,ret);
            m_recv_length += ret;
            //we decided to limit lenth of recv buffer.so we check it

            //TODO something ,NOTICE: ensure m_recv_offset will have changed!!
            //example: on_read();this function shouldn't control by user,it should be control by protocol implementator
            if(m_recv_length >= 16 ){
                if(m_recv_offset > (m_recv_length - m_recv_offset)){
                    print_msg("resize buffer");
                    memcpy(m_recv_buff,m_recv_buff + m_recv_offset,m_recv_length - m_recv_offset);
                    m_recv_buff = (unsigned char *)realloc(m_recv_buff,m_recv_length - m_recv_offset);
                    m_recv_length = m_recv_length - m_recv_offset;
                    m_recv_offset = 0;
                } else {
                    //TODO given out a warning or write to log file. etc
                    print_msg("recv buffer to long!");
                }
            }else{

            }
            this->setEventType(EV_WRITE);
            m_reactor->registerEvent(this,TIMEOUT_READ);
        }
    }
    return data;
}

void * RWEvent::write(void *data){
    print_msg("write event!");
    char buf[] = "I'm rw event";
    const int max_size = sizeof(buf);
    int offset = 0;
    while(true){
        if(m_recv_length - m_recv_offset > 0){
            int ret = send(m_handle,m_recv_buff+m_recv_offset,m_recv_length - m_recv_offset,0);
//            int ret = send(m_handle,m_recv_buff+m_recv_offset,(m_recv_length - m_recv_offset)/2,0);

            if( ret < 0){
                if(errno == EAGAIN){
                    print_msg("send buffer full");
                }
            }else{
                m_recv_offset += ret;
            }
            setEventType(EV_READ);
            m_reactor->registerEvent(this,TIMEOUT_READ);
            return data;
        }
//        int ret = send(m_handle,buf,max_size,0);
//        offset += ret;
//        if(offset >= max_size){
//            setEventType(EV_READ);
//            m_reactor->registerEvent(this,TIMEOUT_READ);
//            return data;
//        }
//        if(ret < 0 || offset == max_size){
//            if(errno == EAGAIN){
//                setEventType(EV_READ);
//                m_reactor->registerEvent(this,TIMEOUT_READ);
//                return data;
//            }
//        }
    }
}

void * RWEvent::timeout(void *data){
    print_msg("RW timeout!");
    return data;
}

void * RWEvent::error(void *data){
    print_msg("disconnect");
    return data;
}

}
